/*
 * Circle.java
 *
 * Created on November 4, 2006, 11:09 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package edu.umn.cs5115.scheduler.circle;

import edu.umn.cs5115.scheduler.framework.ManagedData;

import java.util.ArrayList;
import java.util.HashMap;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;

/**
 *
 * @author grant
 */
public class Circle extends ManagedData
{
    // These are key constants, used for accessing data and registering for
    // notifications using the generic methods.
    public static final String NAME_KEY = "name";
    public static final String RADIUS_KEY = "radius";
    public static final String CENTER_KEY = "center";
    public static final String CENTER_X_KEY = "centerX";
    public static final String CENTER_Y_KEY = "centerY";
    public static final String AREA_KEY = "area";
    public static final String COLOR_KEY = "color";
    public static final String COLOR_RED_KEY = "red";
    public static final String COLOR_GREEN_KEY = "green";
    public static final String COLOR_BLUE_KEY = "blue";
    
    /** This is a class static initializer.  It runs once, the first time the
     * class is used. */
    static
    {
        // Set up dependent keys.  This allows us to change the values these 
        // keys are dependent on, and have notifications automatically sent out.
        ArrayList radiusKey = new ArrayList(1);
        radiusKey.add(RADIUS_KEY);
        setKeysTriggerNotificationForDependentKey(Circle.class, radiusKey, AREA_KEY);
        ArrayList colorKeys = new ArrayList(3);
        colorKeys.add(COLOR_RED_KEY);
        colorKeys.add(COLOR_GREEN_KEY);
        colorKeys.add(COLOR_BLUE_KEY);
        setKeysTriggerNotificationForDependentKey(Circle.class, colorKeys, COLOR_KEY);
        ArrayList centerKeys = new ArrayList(2);
        centerKeys.add(CENTER_X_KEY);
        centerKeys.add(CENTER_Y_KEY);
        setKeysTriggerNotificationForDependentKey(Circle.class, centerKeys, CENTER_KEY);
        
        // set up default values for newly-created Circles.  We could also do this
        // in the constructor.
        HashMap defaultValues = new HashMap();
        defaultValues.put(NAME_KEY, "Untitled Circle");
        defaultValues.put(RADIUS_KEY, 50);
        defaultValues.put(CENTER_X_KEY, 75);
        defaultValues.put(CENTER_Y_KEY, 75);
        defaultValues.put(COLOR_RED_KEY, 255);
        defaultValues.put(COLOR_GREEN_KEY, 0);
        defaultValues.put(COLOR_BLUE_KEY, 0);
        setDefaultValues(Circle.class, defaultValues);
    }
    
    /** Creates a new instance of Circle
     * @param document The document this circle is inside of.
     */
    public Circle(CircleDocument document)
    {
        super(document);
        
        // We used to do initialization here, but I moved it to the static
        // initializer and used the defaults system instead.  If we did it
        // here, we'd want to remember to disable undo registration first
        // so that our initialization can't be undone.
        //document.getUndoManager().disableUndoRegistration();
        //setName("Untitled Circle");
        //setRadius(50);
        //setCenter(new Point(75, 75));
        //setColor(new RGB(255, 0, 0));
        //document.getUndoManager().enableUndoRegistration();
    }
    
    public void setName(String name)
    {
        if (name != null)
            setPrimitiveValueForKey(NAME_KEY, name);
    }
    
    public String getName()
    {
        return getPrimitiveValueForKey(NAME_KEY).toString();
    }
    
    public void setRadius(double radius)
    {
        if (radius >= 0)
            setPrimitiveValueForKey(RADIUS_KEY, radius);
    }
    
    public double getRadius()
    {
        return ((Number)getPrimitiveValueForKey(RADIUS_KEY)).doubleValue();
    }
    
    public void setCenter(Point center)
    {
        setCenterX(center.x);
        setCenterY(center.y);
    }
    
    public Point getCenter()
    {
        return new Point(getCenterX(), getCenterY());
    }
    
    public void setCenterX(int x)
    {
        setPrimitiveValueForKey(CENTER_X_KEY, x);
    }
    
    public int getCenterX()
    {
        return ((Number)getPrimitiveValueForKey(CENTER_X_KEY)).intValue();
    }
    
    public void setCenterY(int y)
    {
        setPrimitiveValueForKey(CENTER_Y_KEY, y);
    }
    
    public int getCenterY()
    {
        return ((Number)getPrimitiveValueForKey(CENTER_Y_KEY)).intValue();
    }
    
    public void setArea(double area)
    {
        if (area > 0)
            setRadius(Math.sqrt(area/Math.PI));
    }
    
    public double getArea()
    {
        double r = getRadius();
        return Math.PI*r*r;
    }
    
    public RGB getColor()
    {
        RGB colorValues = new RGB(getRed(), getGreen(), getBlue());
        return colorValues;
    }
    
    public void setColor(RGB colorValues)
    {
        setRed(colorValues.red);
        setGreen(colorValues.green);
        setBlue(colorValues.blue);
    }
    
    /**
     * Clamps the value to the given range.
     * @param value The value to adjust
     * @param lowerBound The lower bound.
     * @param upperBound the upper bound.
     * @return If value is less than lowerBound, lowerBound is returned.  If 
     * value is between lowerBound and upperBound, value is returned.  If value
     * is greater than upperBound, upperBound is returned.
     */
    private int closestValueInRange(int value, int lowerBound, int upperBound)
    {
        if (value < lowerBound)
            return lowerBound;
        if (value > upperBound)
            return upperBound;
        return value;
    }
    
    public void setRed(int red)
    {
        red = closestValueInRange(red, 0, 255);
        setPrimitiveValueForKey(COLOR_RED_KEY, red);
    }
    
    public int getRed()
    {
        return ((Number)getPrimitiveValueForKey(COLOR_RED_KEY)).intValue();
    }
    
    public void setGreen(int green)
    {
        green = closestValueInRange(green, 0, 255);
        setPrimitiveValueForKey(COLOR_GREEN_KEY, green);
    }
    
    public int getGreen()
    {
        return ((Number)getPrimitiveValueForKey(COLOR_GREEN_KEY)).intValue();
    }
    
    public void setBlue(int blue)
    {
        blue = closestValueInRange(blue, 0, 255);
        setPrimitiveValueForKey(COLOR_BLUE_KEY, blue);
    }
    
    public int getBlue()
    {
        return ((Number)getPrimitiveValueForKey(COLOR_BLUE_KEY)).intValue();
    }
}
